package org.teamh.gui.mapeditor;

import static org.lwjgl.opengl.GL11.*;


import java.awt.Point;
import java.io.BufferedReader;
import java.io.File;
import java.io.FileReader;
import java.io.IOException;
import java.util.HashMap;
import java.util.LinkedList;

import org.lwjgl.util.glu.Disk;
import org.teamh.gui.GUI;
import org.teamh.gui.engine.texture.Texture;
import org.teamh.gui.engine.texture.TextureLoaderCAC;
import org.teamh.gui.mapeditor.MapEditorError;

public class MapEditorFunctions {
	
	private GUI gui;
	private Disk disk = new Disk();
	private String tex_string;
	private Texture[] creep= new Texture[8];
	private Texture texture;
	private File textureFile;
	private Texture redX = TextureLoaderCAC.getTexture("res/img/mapeditor/rotesX.png");
	private Texture attention = TextureLoaderCAC.getTexture("res/img/mapeditor/achtung.gif");
	private LinkedList<Point> path = new LinkedList<Point>();
	private LinkedList<Point> betweenPath = new LinkedList<Point>();
	private LinkedList<MapEditorError> errors = new LinkedList<MapEditorError>();
	private LinkedList<Point> points = new LinkedList<Point>();
	private LinkedList<Point> points_copy= new LinkedList<Point>();
	private HashMap<Point, Float> distance= new HashMap<Point, Float>();
	private HashMap<Point, Integer> direction= new HashMap<Point, Integer>();
	private HashMap<Point, Integer> count = new HashMap<Point, Integer>();
	
	private int[][] constructible = new int[16][16];
	private Point startPoint;
	private Point endPoint;
	public Point selectedPoint;
	public int selectedIndex;
	public int selectedCount;
	public int selectedPathIndex;
	private int barSize; 
	private int size;
	private int leftSpace = 0;
	private int upperSpace = 0;
	private int halfCell= 16;
	private int fieldSize;
	private Point lastPathPoint = null;
	private File buffer;
	private boolean saved = true;
	private boolean walk= false;
	private int currentPoint=0;
	private float currentDistance=0;
	private float speed= 5;
	private int creepPicture=1;
	private int countPoints=0;
	private float countSeconds;
	
	public MapEditorFunctions(GUI gui){
		this.gui = gui;

		texture = TextureLoaderCAC.getTexture("res/img/mapeditor/blank.jpg");
		creep[0]= TextureLoaderCAC.getTexture("res/img/mapeditor/0.jpg");
		creep[1]= TextureLoaderCAC.getTexture("res/img/mapeditor/0.jpg");
		creep[2]= TextureLoaderCAC.getTexture("res/img/mapeditor/1.jpg");
		creep[3]= TextureLoaderCAC.getTexture("res/img/mapeditor/1.jpg");
		creep[4]= TextureLoaderCAC.getTexture("res/img/mapeditor/2.jpg");
		creep[5]= TextureLoaderCAC.getTexture("res/img/mapeditor/2.jpg");
		creep[6]= TextureLoaderCAC.getTexture("res/img/mapeditor/3.jpg");
		creep[7]= TextureLoaderCAC.getTexture("res/img/mapeditor/3.jpg");
		buffer = new File("src/res/img/mapeditor/blank.jpg");

		for(int i = 0; i < constructible.length;i++){
			for(int j = 0; j < constructible[0].length;j++){
				constructible[i][j] = 0;
			}
		}
		
		createDimensions();
		
	}

	/**
	 * reset all variables for the map. Cleans everything and keeps only the GUI settings.
	 */
	public void newMap(){
		saved = true;
		textureFile = new File("src/res/img/mapeditor/blank.jpg");
		texture = TextureLoaderCAC.getTexture("res/img/mapeditor/blank.jpg");
		path.clear();
		betweenPath.clear();
		startPoint = null;
		endPoint = null;
		lastPathPoint = null;
		errors.clear();
		gui.getMapEditorScreen().getController().clearList();
		for(int i = 0; i < constructible.length;i++){
			for(int j = 0; j < constructible[0].length;j++){
				constructible[i][j] = 0;
			}
		}
		selectedPoint = null;
		selectedIndex = 0;
		selectedCount = 0;
		selectedPathIndex = 0;
		
	}
	public void pathpoints(LinkedList<Point> testMe){
		for(Point e:testMe){
			System.out.println(e);
		}
	}
	public void resetWalkCreep(){

		distance.clear();
		direction.clear();
		points_copy.clear();
		points.clear();
		count.clear();
		currentPoint=0;
		currentDistance=0;
		countSeconds=0;
		walk = false;
	}
	
	private void runCreep() {
		float x = (float) points.get(currentPoint).getX();
		float y = (float) points.get(currentPoint).getY();

		if (count.containsKey(points.get(currentPoint))&& countSeconds <= count.get(points.get(currentPoint))) {
			countSeconds += 0.05;
			renderCreep(x, y);
		} else {
			if (direction.get(points.get(currentPoint)) == null) {
				resetWalkCreep();
				return;
			}
			switch (direction.get(points.get(currentPoint))) {
			case 0:
				x += currentDistance;
				break;
			case 1:
				x += currentDistance;
				y -= currentDistance;
				break;
			case 2:
				y -= currentDistance;
				break;
			case 3:
				x -= currentDistance;
				y -= currentDistance;
				break;
			case 4:
				x -= currentDistance;
				break;
			case 5:
				x -= currentDistance;
				y += currentDistance;
				break;
			case 6:
				y += currentDistance;
				break;
			case 7:
				x += currentDistance;
				y += currentDistance;
				break;
			}

			currentDistance += distance.get(points.get(currentPoint)) / speed
					* 1 / 12;
			if (currentDistance > distance.get(points.get(currentPoint))) {
				currentDistance = 0;
				countSeconds = 0;
				currentPoint++;
				x = (float) points.get(currentPoint).getX();
				y = (float) points.get(currentPoint).getY();
				if (currentPoint > points.size() - 1) {
					resetWalkCreep();
				}
			}
			renderCreep(x, y);
		}
	}
	
	private void renderCreep(float x, float y) {
		if (creepPicture == 7) {
			creepPicture = 0;
		} else {
			creepPicture++;
		}
		creep[creepPicture].bind();
		glColor3f(1, 1, 1);
		glEnable(GL_TEXTURE_2D);
		{
			glBegin(GL_QUADS);
			{
				glTexCoord2f(1, 1);
				glVertex2d(x + halfCell, y + halfCell);
				glTexCoord2f(1, 0);
				glVertex2d(x + halfCell, y - halfCell);
				glTexCoord2f(0, 0);
				glVertex2d(x - halfCell, y - halfCell);
				glTexCoord2f(0, 1);
				glVertex2d(x - halfCell, y + halfCell);
			}
			glEnd();
		}
		glDisable(GL_TEXTURE_2D);
	}
	
	private void initWalk(){
		distance.clear();
		direction.clear();
		points_copy.clear();
		points.clear();
		count.clear();
		fillLinkedListPoints();
		fillDistanceHashMap();
		runCreep();
	}
	
	@SuppressWarnings("unchecked")
	private void fillLinkedListPoints() {
//		points_copy.add(startPoint);
//		for(Point p: path){
//			points_copy.add(p);
//		}
		
		points_copy = (LinkedList<Point>) path.clone();
		points_copy.addFirst(startPoint);
		points_copy.add(endPoint);
		pointCounter();
	}
	
	private void pointCounter() {
		points.add(points_copy.get(0));
		for(int i= 1; i<points_copy.size();i++){
			int j=i;
			if(j+1<points_copy.size()){
				while(	points_copy.get(j).getX()==points_copy.get(j+1).getX()&&
						points_copy.get(j).getY()==points_copy.get(j+1).getY()	){
					countPoints++;
					j++;
				}	
			}
			
			if(countPoints>0){
				countPoints++;
				points.add(points_copy.get(j));
				count.put(points_copy.get(j), countPoints);
				countPoints=0;
			}else{
				points.add(points_copy.get(i));
			}
			i=j;
		}
	}

	private void fillDistanceHashMap() {
		for(int i=0; i<points.size();i++){
			if(i+1<points.size()){
				countDistance(points.get(i),points.get(i+1));
			}
		}
	}

	private void countDistance(Point current, Point next) {
		float distanceX=(float)(current.getX()-next.getX());
		float distanceY=(float)(current.getY()-next.getY());
		if(Math.abs(distanceX)>Math.abs(distanceY)){
			distance.put(current, Math.abs(distanceX));
		}else{
			if(distanceX==0 && distanceY==0){
				distance.put(current, 0f);
			}else{
				distance.put(current, Math.abs(distanceY));
			}
		}
		determineDirection(distanceX, distanceY, current);
	}

	private void determineDirection(float x, float y, Point current) {

		if (x < 0 && y == 0) {
			direction.put(current, 0);
		}
		if (x == 0 && y > 0) {
			direction.put(current, 2);
		}
		if (x > 0 && y > 0) {
			direction.put(current, 3);
		}
		if (x < 0 && y > 0) {
			direction.put(current, 1);
		}
		if (x > 0 && y == 0) {
			direction.put(current, 4);
		}
		if (x < 0 && y < 0) {
			direction.put(current, 7);
		}
		if (x == 0 && y < 0) {
			direction.put(current, 6);
		}
		if (x > 0 && y < 0) {
			direction.put(current, 5);
		}
	}


	public int[][] getConstructable(File map) throws IOException {
		 FileReader fr = new FileReader(map); 
		 BufferedReader br = new BufferedReader(fr);
		 
		 int[][] mapCords = new int[16][16];

		 String line = br.readLine();

		 while (line != null) {
			 if (!line.startsWith("#")&&!line.isEmpty()) {
				 if(line.contains(";")) {
					 String[] str = line.split(";");
					
					 int x = Integer.parseInt(str[0]);
					 int y = 0;
					 String help = "";
					 
					 if (str[1].contains(" ")) {
						help = str[1].replace(" ", "");
						y = Integer.parseInt(help);
					 } else {
						 y = Integer.parseInt(str[1]);
					 }
					 
					 mapCords[x][y] = 2;
				 } else if (line.contains(",")) {
					 String[] str = line.split(",");
					
					 int x = Integer.parseInt(str[0]);
					 int y = 0;
					 String help;
					 
					 if (str[1].contains(" ")) {
						 help = str[1].replace(" ", "");
						 y = Integer.parseInt(help);
					 } else {
						 y = Integer.parseInt(str[1]);
					 }
					 mapCords[x][y] = 1;
				 }
			 }
			 line = br.readLine();
		 }
		 br.close();
		 
		 return mapCords;
	}
	
	public LinkedList<Point> getPath(File mapPath) throws IOException {
		
		LinkedList<Point> pathWay = new LinkedList<Point>();
		
		 FileReader fr = new FileReader(mapPath); 
		 BufferedReader br = new BufferedReader(fr);
		 Point lastPoint = null;
		 int i = 0;
		 
		 String line = br.readLine();

		 while (line != null) {
			 if (!line.startsWith("#")&&!line.isEmpty()) {
				 if (line.contains(",")) {
					String[] str = line.split(",");
					 if(i == 0) {
						 int helpY = 0;
						 
						 int x = (Integer.parseInt(str[0]) + 1)*fieldSize + (leftSpace/2);
						 String help;
						 
						 if (str[1].contains(" ")) {
							 help = str[1].replace(" ", "");
							 helpY = Integer.parseInt(help);
						 } else {
							 helpY = Integer.parseInt(str[1]);
						 }
						 
						 int y = (helpY + 1)*fieldSize + (upperSpace/2);
						 
						 startPoint = centerCoordinates(new Point(x, y));
						 i++;
					 }
					 
					 int y = 0;
					 String help = "";
					 
					 if (str[1].contains(" ")) {
						 help = str[1].replace(" ", "");
						 y = Integer.parseInt(help);
					 } else {
						 y = Integer.parseInt(str[1]);
					 }
					 
					lastPoint = new Point(Integer.parseInt(str[0]), y);
					pathWay.add(lastPoint);	
				}
			 }
			 line = br.readLine();
		 }
		 if (pathWay.size() > 0) {
			 pathWay.removeFirst();
			 pathWay.removeLast();
			 int x = (int) ((lastPoint.getX() + 1)*fieldSize + (leftSpace/2));
			 int y = (int) ((lastPoint.getY() + 1)*fieldSize + (upperSpace/2));
			 lastPoint = new Point(x, y);
			 endPoint = centerCoordinates(lastPoint);
		 }
		 br.close();

		return pathWay;
	}
	
	public Point test(Point p) {
		
		int x = (int) ((p.getX() + 1)*fieldSize + (leftSpace/2));
		int y = (int) ((p.getY() + 1)*fieldSize + (upperSpace/2));
		return new Point(x,y);
	}
	
	private void createDimensions(){
		barSize = (int) ((gui.getHeight()/768d)*280);
		size = gui.getWidth()-barSize;
		if(size>gui.getHeight()){
			size = gui.getHeight();
		}
		while((size%16) != 0){
			size--;
		}
		upperSpace = gui.getHeight() - size;
		leftSpace = gui.getWidth() - barSize - size;
		fieldSize = size/16;
	
		
	}
	
	
	public void render(){
		if (textureFile != null) {
			texture = TextureLoaderCAC.getTexture(textureFile);
			buffer = textureFile.getAbsoluteFile();
			textureFile = null;
		}
		
		glMatrixMode(GL_PROJECTION);
		glPushMatrix();
		{
			glLoadIdentity();

			glOrtho(0, gui.getWidth(), gui.getHeight(), 0, -9999, 9999);

			glMatrixMode(GL_MODELVIEW);
			glPushMatrix();
			{
				glLoadIdentity();
				glDisable(GL_DEPTH_TEST);
				glEnable(GL_BLEND);
				glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
				
				renderMap(tex_string);
				
				glDisable(GL_BLEND);
				glEnable(GL_DEPTH_TEST);
			}
			glPopMatrix();
			glMatrixMode(GL_PROJECTION);
		}
		glPopMatrix();
		glMatrixMode(GL_MODELVIEW);
	}
	
	private void renderMap(String tex_string){
		//glColor3f(1, 0, 1);
		//renderQuad(10,10,20,20);
		//renderCircle(100, 200, 6);
		glColor3f(1, 1, 1);
		renderTexture(texture,(leftSpace / 2), (upperSpace/2), (int) size,(int) size);
		drawConstructible();
		drawGrid();
		drawStartEnd(1f,0.1f,1f);
		drawPath(1,1,1);
		drawDraggedLine();
		drawErrors();
		if(walk){
			initWalk();
		}
		//glColor4f(1, 0, 1, 0.5f);
		//renderQuad(10,10,20,20);
	}
	private void drawErrors() {
		if(lastPathPoint == null)
			sanityCheck();
		for(MapEditorError current:errors){
			glColor3f(1,1,0);
			renderCircle((float) current.getStart().getX(),(float) current.getStart().getY(),(float) (size*0.02));
			renderCircle((float) current.getEnd().getX(),(float) current.getEnd().getY(),(float) (size*0.02));
			renderLine(current.getStart(), current.getEnd());
			renderTexture(attention, (int) ((current.getStart().getX()+current.getEnd().getX())/2), (int) (((current.getStart().getY()+current.getEnd().getY())/2) + 20), 20, 20);
		}
		
	}

	public void changeBackground(File tex_file){
		texture = TextureLoaderCAC.getTexture(tex_file);
	}
	
	/**
	 * The function will set the start Point as well as the End Point, according to the Start Point, so Start and End Points match while rotating the map.
	 * The Start Point can only placed in the row at the lower end.
	 * @param start
	 */
	public void setStartPoint(Point start){
		if(isInField(start) && start.getY() > (size + (upperSpace/2) - (size/16))){
			if(startPoint != null){
				constructible(startPoint, 0);
				constructible(endPoint, 0);
			}
			Point tempPoint = startPoint;
			startPoint = centerCoordinates(start);
			constructible(startPoint, 1);
			double endX = startPoint.getY()-(upperSpace/2)+(leftSpace/2);
			double endY = startPoint.getX()-(leftSpace/2)+(upperSpace/2);
			endPoint = new Point((int) endX, (int) endY);
			constructible(endPoint, 1);
			saved = false;
			if(selectedPoint == null || selectedPoint == tempPoint){
				selectedPoint = startPoint;
				selectedPathIndex = -1;
				selectedIndex = -1;
			}
		}
	}
	/**
	 * Add new Points to the Path. Points can only be added, if the degree to the previous Point is a 90� angle. 
	 * If the dragged attribute is set, the next point will be set when there is a direction change while dragging, or the mouse is released.
	 * @param point current mouse point
	 * @param dragged
	 */
	public void addPointsToPath(Point point, boolean dragged){
		if(isInField(point) && startPoint != null){
			

			
			Point lastPoint;
			point = (centerCoordinates(point));

			//used to increase the number of the selected point
			if(path.contains(point) && lastPathPoint == null){
				int count = countUpWaypoints(point);
				if(point.equals(selectedPoint)){
					gui.getMapEditorScreen().getController().deletePointFromList(createListItemString(point, selectedIndex, count));
					addPoint(point, selectedIndex, true);
				}
				else{
					int index = getListIndex(point);
					selectByIndex(index);
					gui.getMapEditorScreen().getController().selectItemFromList(createListItemString(point, index, count));
					
				}
				
				saved = false;
				return;
			}
			lastPoint = selectedPoint;

			double degree = (Math.atan2(point.getY() - lastPoint.getY(), point.getX() - lastPoint.getX()) * 180 / Math.PI);
			boolean isDegree = ((degree == 135) || (degree == -135) || (degree == 45) || (degree == -45));
			
			if(dragged){
				int index;
				if(point.getX() == lastPoint.getX() ^ point.getY() == lastPoint.getY() || isDegree){
					lastPathPoint = point;
				} 
				else {
					if((lastPathPoint != null) && (point.getX() == lastPathPoint.getX() || point.getY() == lastPathPoint.getY()  || isDegree)){
						if(selectedPoint == startPoint)
							index = 0;
						else
							index = selectedIndex+1;
						addPoint(lastPathPoint, index, false);
					}
					if(point.getX() == lastPoint.getX() || point.getY() == lastPoint.getY() || isDegree){
						lastPathPoint = point;
					}
				}
				
			}
			else{
				int index;
				if(point.getX() == lastPoint.getX() || point.getY() == lastPoint.getY()  || isDegree){
					if(selectedPoint == startPoint)
						index = 0;
					else
						index = selectedIndex+1;
					addPoint(point, index, false);
				}
			}
		}
	}
	/**
	 * Only important for the dragged path so far.
	 * Adds the last dragged Point to the Path.
	 * @param point
	 */
	public void mouseReleased(Point point){
		Point lastPoint;
		point = (centerCoordinates(point));
		
			if(!path.isEmpty())
				lastPoint = selectedPoint;
			else
				lastPoint = startPoint;

		if(lastPathPoint != null){
			double degree = (Math.atan2(point.getY() - lastPoint.getY(), point.getX() - lastPoint.getX()) * 180 / Math.PI);
			boolean isDegree = ((degree == 135) || (degree == -135) || (degree == 45) || (degree == -45));
			int index;
			if(lastPathPoint.getX() == lastPoint.getX() ^ lastPathPoint.getY() == lastPoint.getY() || isDegree){
				if(selectedPoint.equals(startPoint)){
					index = 0;
				}
				else
					index = selectedIndex+1;
				addPoint(lastPathPoint, index, false);
					
			}
			lastPathPoint = null;
		}
		
	}
	
	private void addPoint(Point toAdd, int index, boolean countUP){

		constructible(toAdd, 2);
		constructibleBetweenPoints(selectedPoint, toAdd, 2);
		int number = 1;

		//Index for the GUI List
		int selindex = selectedIndex+1;
		if(selectedPoint == startPoint)
			selindex = 0;
		if(countUP){
			selectedCount++;
			selindex = selectedIndex;
			number = selectedCount;
		}
		Point delPathPoint;
		if(selectedPathIndex > 0){
			if(selectedPathIndex == path.size()-1){
				delPathPoint = endPoint;
			}
			else{
				delPathPoint = path.get(selectedPathIndex+1);
			}
			constructibleBetweenPoints(path.get(selectedPathIndex), delPathPoint, 0);
		}
			
		path.add(selectedPathIndex+1, toAdd);
		gui.getMapEditorScreen().getController().addPointToList(createListItemString(toAdd, selindex, number), selindex);
		saved = false;
		redoList();
		selectByIndex(selindex);
		gui.getMapEditorScreen().getController().selectItemFromList(createListItemString(toAdd, selindex, number));
		pathConstructible();
	}
	public void addPointstoList(LinkedList<Point> path){
		System.out.println("addPoints");
		Point lastPoint = null;
		int i = 1;
		int j = 0;
		for(Point point: path){
			if(lastPoint != null){
				if(lastPoint == point){
					i++;
				}
				else{
					gui.getMapEditorScreen().getController().addPointToList(createListItemString(lastPoint, j,i), j);
					j++;
					lastPoint = point;
					i = 1;
				}
			}
			else{
				lastPoint = point;
				i = 1;
			}
		}
		gui.getMapEditorScreen().getController().addPointToList(createListItemString(lastPoint, j, i), j);
		gui.getMapEditorScreen().getController().selectItemFromList(createListItemString(lastPoint, j, i));
		selectedPoint = lastPoint;
	}
	public int getListIndex(Point point){
		int i = 0;
		Point lastPoint = null;
		for(Point e : path){
			if(e.getX() == point.getX() && e.getY() == point.getY())
				break;
			if(lastPoint != null && lastPoint != e)
				i++;
			if(lastPoint == null)
				i++;
			lastPoint = e;
		}
		return i;
	}
	public void printPoints(Point specific){
		for(Point i: path){
			if(i == specific){
				System.out.print("_CURRENT_");
			}
			System.out.print("ID: "+ path.indexOf(i) + " X: " + i.getX() + " Y: " + i.getY() + " - ");
		}
		System.out.println();
	}
	
	
	/**
	 * Delete a Point with this function. The Point will only be replaced with an -1/-1 location Point, to symbolize the cut in the Path.
	 * @param toDelete
	 */
	public void deletePath(Point toDelete){
		toDelete = centerCoordinates(toDelete);
		for(Point e:path){
			if(e.getX() == toDelete.getX() && e.getY() == toDelete.getY()){
				int index = getListIndex(toDelete);
				selectByIndex(index);
				if(selectedCount > 1){
					gui.getMapEditorScreen().getController().deletePointFromList(createListItemString(toDelete, index, selectedCount));
					gui.getMapEditorScreen().getController().addPointToList(createListItemString(toDelete, index, --selectedCount), path.indexOf(e));
				}
				else{
					constructible(e,0);
					gui.getMapEditorScreen().getController().deletePointFromList(createListItemString(toDelete, index, selectedCount));

					
					if(path.indexOf(e)>0){
						
						constructibleBetweenPoints(e, path.get(path.indexOf(e)-1), 0);
						
					}
					else{
						constructibleBetweenPoints(e, startPoint, 0);
						selectedPoint = startPoint;
						selectedPathIndex = -1;
						selectedIndex = -1;
						
					}
					if(path.size()-1 > path.indexOf(e))
						constructibleBetweenPoints(e, path.get(path.indexOf(e)+1), 0);
					if(path.size()-1 == path.indexOf(e))
						constructibleBetweenPoints(e, endPoint, 0);
					index--;
				}			
				path.remove(e);
				redoList();
				if(!selectedPoint.equals(startPoint))
						selectByIndex(index);
				gui.getMapEditorScreen().getController().selectItemFromList(createListItemString(selectedPoint, index, selectedCount));
				pathConstructible();
				break;
			}
			saved = false;
		}
			
		}
	public void redoList(){
		gui.getMapEditorScreen().getController().clearList();
		Point lastPoint = null;
		int i = 1;
		int j = 0;
		for(Point e: path){
			if(lastPoint != null){
				if(lastPoint.equals(e))
					i++;
				else{
					gui.getMapEditorScreen().getController().addPointToList(createListItemString(lastPoint, j, i), j);
					i = 1;
					j++;
					lastPoint = e;
				}
			}
			else{
				lastPoint = e;
			}
		}
		if(!path.isEmpty())
			gui.getMapEditorScreen().getController().addPointToList(createListItemString(lastPoint, j, i), j);
	}
	
	/**
	 * The Constructible Array defines the places where something can be placed. It has 3 different settings (for Action):<br>
	 * <ul>
	 * <li>0 - field is fully constructible</li>
	 * <li>1 - field is not constructible, but is not shown in the MapEditor (e.g. for the path)
	 * <li>2 - field is not constructible and it's shown in the MapEditor
	 * </ul>
	 * @param toDo the Point to get 'constructified'
	 * @param action the number, according to the declaration above, to be set
	 */
	
	public void constructible(Point toDo, int action){
		if(isInField(toDo)){
			int x = 1;
			int y = 1;
			while(((x*fieldSize)+(leftSpace/2)) < toDo.getX()){
				x++;
			}
			while(((y*fieldSize)+(upperSpace/2)) < toDo.getY()){
				y++;
			}
			y--;
			x--;
			constructible[x][y] = action;
			saved = false;
		}
	}
	
	
	private void drawDraggedLine(){
		if(lastPathPoint != null){
	
			glColor4f(1, 0, 0, 0.5f);
			renderLine(selectedPoint, lastPathPoint);
		}
	}
	
	
	private void constructibleBetweenPoints(Point a, Point b, int constructible){
		double lengthX;
		double lengthY;
		
		lengthX = Math.abs(a.getX() - b.getX());
		lengthY = Math.abs(a.getY() - b.getY());
		int xSign = -1;
		int ySign = -1;
		if(a.getX()<b.getX())
			xSign = 1;
		if(a.getY()<b.getY())
			ySign = 1;
//		System.out.println("Constr X: " + lengthX);
//		System.out.println("Constr Y: " + lengthY);
		while(lengthX>=fieldSize || lengthY>=fieldSize){
			constructible(new Point((int) (a.getX()+(xSign * lengthX)),(int) (a.getY()+(ySign * lengthY))), constructible);
//			System.out.println(new Point((int) (a.getX()+(xSign * lengthX)),(int) (a.getY()+(ySign * lengthY))));
			if(lengthX>0)
				lengthX= lengthX - fieldSize;
			if(lengthY>0)
				lengthY= lengthY - fieldSize;
		}
		/*
		if((lengthX = Math.abs(a.getX() - b.getX())) > 0){
			temp = a;
			if(a.getX()<b.getX())
				temp = b;
			while(lengthX>=fieldSize){
				constructible(new Point((int) (temp.getX()-lengthX),(int) temp.getY()), constructible);

				lengthX= lengthX - fieldSize;
			}
		}
		if((lengthY = Math.abs(a.getY() - b.getY())) > 0){
			temp = a;
			if(a.getY()<b.getY())
				temp = b;
			while(lengthY>=fieldSize){
				constructible(new Point((int) temp.getX(),(int) (temp.getY()-lengthY)), constructible);

				lengthY= lengthY - fieldSize;
			}
		}
		*/
		saved = false;
	}
	
	private void pathConstructible(){
		if(!path.isEmpty()){
			Point lastPoint = startPoint;
			for(Point e: path){
				double degree = (Math.atan2(e.getY() - lastPoint.getY(), e.getX() - lastPoint.getX()) * 180 / Math.PI);
				boolean isDegree = ((degree == 135) || (degree == -135) || (degree == 45) || (degree == -45));

				if(e.getX() == lastPoint.getX() ^ e.getY() == lastPoint.getY() || isDegree)
					constructibleBetweenPoints(lastPoint,e, 2);
				lastPoint = e;
			}
			double degree = (Math.atan2(endPoint.getY() - lastPoint.getY(), endPoint.getX() - lastPoint.getX()) * 180 / Math.PI);
			boolean isDegree = ((degree == 135) || (degree == -135) || (degree == 45) || (degree == -45));

			if(endPoint.getX() == lastPoint.getX() ^ endPoint.getY() == lastPoint.getY() || isDegree)
				constructibleBetweenPoints(lastPoint,endPoint, 2);
		}
	}
	
	private void drawConstructible(){
		for(int i = 0; i < constructible.length;i++){
			for(int j = 0; j < constructible[0].length;j++){
				if(constructible[i][j] == 2){
					glColor3f(1, 1, 1);
					renderTexture(redX,i*fieldSize + (leftSpace/2),j*fieldSize + (upperSpace/2),fieldSize,fieldSize);
				}
				
			}
		}
	}
	
	
	private boolean isInField(Point check){
		if(check.getX()<(leftSpace/2) || check.getX()>((leftSpace/2) + size))
			return false;
		if(check.getY()<(upperSpace/2) || check.getY()>((upperSpace/2) + size))
			return false;	
		
		return true;
	}
	
	public Point centerCoordinates(Point toCenter){
		int x = 1;
		while(((x*fieldSize)+(leftSpace/2)) < toCenter.getX()){
			x++;
		}
		x = (((x*fieldSize)+(leftSpace/2)) + (((x-1)*fieldSize))+(leftSpace/2))/2;
		int y = 1;
		while(((y*fieldSize)+(upperSpace/2)) < toCenter.getY()){
			y++;
		}
		y = (((y*fieldSize)+(upperSpace/2)) + (((y-1)*fieldSize)+(upperSpace/2)))/2;
		
		
		
		return new Point(x,y);
	}
	
	
	
	private void drawStartEnd(float red, float green, float blue){
		glColor3f(red, green, blue);
		if(startPoint != null) {
			renderCircle((float) startPoint.getX(), (float) startPoint.getY(), (float) (size*0.01));
			if(endPoint != null) {
				renderCircle((float) endPoint.getX(), (float) endPoint.getY(), (float) (size*0.01));
			}
			if(!path.isEmpty()){
				glColor3f(1, 1, 1);
				renderLine(startPoint,path.getFirst());
				renderLine(endPoint, path.getLast());
			}
		}
	}
	/**
	 * Function draws the main path.<br>
	 * Empty Points are specified by the X/Y Coordinates -1/-1.
	 * The line will be cutted wherever an empty point is.
	 * 
	 */
	private void drawPath(float red, float green, float blue){
	//	gui.getMapEditorScreen().getController().clearList();
		Point lastPoint= null;
		try{
		for(Point i : path){
			glColor3f(red, green, blue);
			if(lastPoint!= null){
				renderLine(lastPoint, i);
			}
			lastPoint = i;
			renderCircle((float) i.getX(), (float) i.getY(),(float) (size*0.01));
			glColor3f(0, 0, 0);
			renderCircle((float) i.getX(), (float) i.getY(),(float) ((size*0.01)/2));
			//gui.getMapEditorScreen().getController().addPointToList("X: " + i.getX() + " Y: " + i.getY());
		}
		lastPoint= null;
		}catch(Exception e){
			//just do nothing .. overlapping error while drawing/deleting
		}
		for(Point i : betweenPath){
			glColor3f(1, 1, 0);
			if(lastPoint!= null){
				renderLine(lastPoint, i);
			}
			lastPoint = i;
			renderCircle((float) i.getX(), (float) i.getY(),(float) (size*0.01));
			glColor3f(0, 0, 0);
			renderCircle((float) i.getX(), (float) i.getY(),(float) ((size*0.01)/2));

		}
		
		glColor3f(1f, 0.5f, 0f);
		if(selectedPoint != null)
			renderCircle((float) selectedPoint.getX(), (float) selectedPoint.getY(),(float) (size*0.01));
		
	}
	
	private void drawGrid(){
		int startUpper = (upperSpace/2);
		int startLeft = (leftSpace/2);
		glColor3f(0, 0, 0);
		for(int i = 0; i<=16; i++){
			int currentField = fieldSize * i;
			renderLine(new Point((startLeft+currentField),startUpper), new Point((startLeft+currentField),(startUpper+16*fieldSize)));
			renderLine(new Point(startLeft,(startUpper+currentField)), new Point((startLeft+16*fieldSize),(startUpper+currentField)));
		}
	}
	/**
	 * Checks the Path for errors. Especial for Number 23 and 47: A Hole in the Path or a non 90�-angle between points. 
	 */
	private void sanityCheck(){
		if(startPoint != null){
			errors.clear();
			
			Point lastPoint = startPoint;
			for(Point compare : path){
				
				double degree = (Math.atan2(compare.getY() - lastPoint.getY(), compare.getX() - lastPoint.getX()) * 180 / Math.PI);
				boolean isDegree = ((degree == 135) || (degree == -135) || (degree == 45) || (degree == -45));				

					if(!(compare.getX() == lastPoint.getX() || compare.getY() == lastPoint.getY() || isDegree)){
						errors.add(new MapEditorError(compare, lastPoint, 47));
					}
					lastPoint = compare;
			}
			
			double degree = (Math.atan2(endPoint.getY() - lastPoint.getY(), endPoint.getX() - lastPoint.getX()) * 180 / Math.PI);
			boolean isDegree = ((degree == 135) || (degree == -135) || (degree == 45) || (degree == -45));
					
			if(!(endPoint.getX() == lastPoint.getX() || endPoint.getY() == lastPoint.getY() || isDegree)){
				errors.add(new MapEditorError(endPoint, lastPoint, 47));
			}
		}
	}
	/**
	 * Creates the serialized String for the List in the GUI
	 * @param point
	 * @param index
	 * @param count
	 * @return
	 */
	private String createListItemString(Point point, int index, int count){
		int x = 1;
		int y = 1;
		while(((x*fieldSize)+(leftSpace/2)) < point.getX()){
			x++;
		}
		while(((y*fieldSize)+(upperSpace/2)) < point.getY()){
			y++;
		}
		
		String string = (index < 100 ? "0" : "") + (index < 10 ? "0" : "") + index + ". X:" +(x < 10 ? "0" : "") + x + " - Y:" + (y < 10 ? "0" : "") + y; 
		if(count > 1)
			string += ", count:" + count;
		return string;
		
	}
	public Point revertListPoint(int X,int Y){
		return new Point(X*fieldSize + (leftSpace/2)-(fieldSize/2),Y*fieldSize + (upperSpace/2)-(fieldSize/2));
	}
	private int countUpWaypoints(Point point){
		int count = 0;
		for(Point e : path){
			if(e.equals(point))
				count++;
		}
		return count;
	}
	public void selectByIndex(int listDex){
//		System.out.println("selectBy: " + listDex);
		int i = 0;
		int j = 0;
		int count = 1;
		Point lastPoint = null;
		boolean dexFound = false;
		boolean selectedSet = false;
		for(Point e : path){
//			System.out.println("i: " + i + " - count: " + count);
			if(lastPoint != null){
				if(lastPoint.equals(e))
					count++;
				else{
					if(dexFound){
						j--;
//						System.out.println("Found by: " + j);
						selectedSet = true;
						selectedPoint = lastPoint;
						selectedIndex = listDex;
						selectedCount = count;
						selectedPathIndex = j;
						break;
					}
					else{
						if(i == listDex){
							dexFound = true;
						}
						count = 1;
						i++;
					}
					lastPoint = e;
				}
			}
			else{
				if(i == listDex){
					dexFound = true;
				}
				i++;
				lastPoint = e;
			}
			j++;
		}
		if(!selectedSet){
			j--;
//			System.out.println("Found by: " + j);
			selectedPoint = lastPoint;
			selectedIndex = listDex;
			selectedCount = count;
			selectedPathIndex = j;
		}
//		System.out.println(selectedIndex + " - " + selectedCount);
		
	}
	
	private void renderLine(Point a, Point b){
		glBegin(GL_LINE_STRIP);
		glVertex2d(a.getX(), a.getY());
		glVertex2d(b.getX(), b.getY());
		glEnd();
	}
	
	private void renderCircle(float x, float y, float r){
		glPushMatrix();
		glTranslatef(x, y, 0);
		disk.draw(r/2, r, 60, 1);
		glPopMatrix();
	}
	
	private void renderTexture(Texture texture, int x, int y, int width, int height){
		glColor3f(1,1,1);
		gui.getHeight();

		glEnable(GL_TEXTURE_2D);
		texture.bind();
		glBegin(GL_QUADS);
		glTexCoord2f(0, 0);
		glVertex2f(x, y);
		glTexCoord2f(1, 0);
		glVertex2f(x+width, y);
		glTexCoord2f(1, 1);
		glVertex2f(x+width, y+height);
		glTexCoord2f(0, 1);
		glVertex2f(x, y+height);
		
		
		glEnd();
		glDisable(GL_TEXTURE_2D);
		
	}
	
	public Point reverseCoords(Point p) {
		double x = (p.getX() - (leftSpace/2)) / fieldSize;
		double y = (p.getY() - (upperSpace/2)) / fieldSize;
		
		return new Point((int) x, (int) y);
	}
	
	public void setTexture(Texture texture) {
		this.texture = texture;
	}
	
	public void setConstructible(int[][] constructible) {
		this.constructible = constructible;
	}
	
	public void setPath(LinkedList<Point> path) {
		this.path = path;
	}

	public File getTextureFile() {
		return textureFile;
	}

	public void setTextureFile(File textureFile) {
		this.textureFile = textureFile;
	}
	
	public int[][] getConstructible() {
		return constructible;
	}
	
	public LinkedList<Point> getPath() {
		return path;
	}
	
	public Point getStartPoint() {
		return startPoint;
	}
	
	public Point getEndPoint() {
		return endPoint;
	}
	
	public String getTex_string() {
		return tex_string;
	}

	public File getBuffer() {
		return buffer;
	}

	public void setBuffer(File buffer) {
		this.buffer = buffer;
	}
	
	public LinkedList<MapEditorError> getErrors() {
		return errors;
	}
	
	public void setSaved(boolean saved) {
		this.saved = saved;
	}
	public boolean isSaved() {
		return saved;
	}
	public void walk(boolean walk){
		this.walk=walk;
	}
	public boolean isWalked() {
		return walk;
	}
	
}
